package org.simp.annotation;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.simp.exception.SimpInitException;
import org.simp.util.ClassUtil;
import org.simp.util.PackUtil;

/**
 * 所有simp请求的管理
 * @author Administrator
 *
 */
public class SimpControllerManager {
	private static final Logger log = Logger.getLogger(SimpControllerManager.class);
	/**
	 * 需要扫描的包名
	 */
	private String scanPacketName;
	
	private Map<String,Object> controllerMap = Collections.synchronizedMap(new HashMap<String,Object>());
	
	private Map<Integer,String > requestMap = Collections.synchronizedMap(new HashMap<Integer,String>());
	
	private Map<Integer,Method> methodMap = Collections.synchronizedMap(new HashMap<Integer,Method>());
	
	private static SimpControllerManager manager = new SimpControllerManager();
	private  boolean hasInit;
	
	private SimpControllerManager (){}
	
	private void initController(){
		String [] scanPackets = scanPacketName.split(",");
		for(String packetName : scanPackets){
			scanPacketName(packetName);
		}
		hasInit = true;
	}
	/**
	 * 根据扫描的包名，创建一个新的manager
	 * @param scanPacketNames
	 * @return
	 * @author zhuhaitao at 2014-5-26
	 */
	public static SimpControllerManager createManager(String scanPacketNames){
		SimpControllerManager instance = new SimpControllerManager();
		instance.scanPacketName = scanPacketNames;
		instance.initController();
		return instance;
	}
	
	public static SimpControllerManager  getManager( String scanPacketNames){
		if(!manager.hasInit){
			manager.scanPacketName = scanPacketNames;
			manager.initController();
		}
		return manager;
	}
	/**
	 * 扫描包名，自动装载包下面注解的handler
	 * @param packetName
	 */
	public void scanPacketName(String packetName){
		List<Class> classSet = ClassUtil.scanPackage(packetName);
		for(Class<?> clazz : classSet){
			
			injectController(clazz);
		}
	}
	
	private void injectController(Class<?> clazz){

		
		SimpController controller =null;
		try{ 
			controller = clazz.getAnnotation(SimpController.class);
		}catch (Exception e) {
//			System.err.println(clazz.getCanonicalName());
		}
		
		if(controller != null){ 
			addController(clazz.getSimpleName(), clazz);
			short mainId = controller.mainId();
			Method[] methods  = clazz.getMethods();
			for(Method method : methods){
				SimpProgress progress = method.getAnnotation(SimpProgress.class);
				if(progress == null){
					continue;
				}
				if(mainId <0){
					mainId = progress.mainId();
				}
				short moudleId = progress.moudleId();
				int requestId = (mainId << 16 & 0xffffffff )|( moudleId &0xffff) ;
				addMethod(requestId, method);
				addRequest(requestId, clazz.getSimpleName());
			}
		}
	
	}

	private void addController(String controllerName,Class<?> controllerClazz){
		
		if(controllerMap.containsKey(controllerName)){
			throw new SimpInitException( controllerName + " has init ");
		}else{
			try {
				Object controller = controllerClazz.newInstance();
				controllerMap.put(controllerName, controller);
			} catch (InstantiationException e) {
				throw new SimpInitException( controllerName + " is not a class",e);
			} catch (IllegalAccessException e) {
				throw new SimpInitException( controllerName + " no public  constructor",e);
			}
		}
	}
	
	private void addRequest(int requestId,String controllerName){
		if(requestMap.containsKey(requestId)){
			SimpInitException e = new SimpInitException(requestId + " has register Controller ");
			throw e;
		}else {
			requestMap.put(requestId, controllerName);
		}
	}
	
	private void addMethod(int requestId,Method method){
		if(methodMap.containsKey(requestId)){
			SimpInitException e = new SimpInitException(requestId + " has register Controller  Method");
			log.error("init Controller error ",e);
			throw e;
		}else{
			methodMap.put(requestId, method);
		}
	}
	/**
	 * 根据协议Id获取controller
	 * @param requestId
	 * @return
	 * @author zhuhaitao at 2014-5-26
	 */
	public Object getController(int requestId){
		String controllerName = requestMap.get(requestId);
		if(controllerName == null || !controllerMap.containsKey(controllerName)){
			return null;
		}
		return controllerMap.get(controllerName);
	}
	/**
	 * 根据协议Id或者controller层方法
	 * @param requestId
	 * @return
	 * @author zhuhaitao at 2014-5-26
	 */
	public Method getMethod(int requestId){
		return methodMap.get(requestId);
	}
	
	public void registerController(Class<?> clazz){
		injectController(clazz);
	}
}
